package com.ssy.lingxi.system.service.impl;

import com.ssy.lingxi.common.response.PageData;
import com.ssy.lingxi.common.response.Wrapper;
import com.ssy.lingxi.system.dao.MenuCodeRepository;
import com.ssy.lingxi.system.entity.MenuCode;
import com.ssy.lingxi.system.model.request.*;
import com.ssy.lingxi.system.model.response.MenuCodeVO;
import com.ssy.lingxi.system.service.MenuCodeService;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import javax.persistence.criteria.Predicate;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 菜单编码相关接口实现类
 * @author 万宁
 * @version 2.0.0
 * @date 2021-01-14
 */
@Service
public class MenuCodeServiceImpl implements MenuCodeService {
    @Resource
    private MenuCodeRepository menuCodeRepository;

    /**
     * 新增菜单编码
     *
     * @param addVO 接口参数
     * @return 操作结果
     */
    @Override
    public Wrapper<Void> addMenuCode(MenuCodeAddVO addVO) {
        if(menuCodeRepository.existsByCodeAndSource(addVO.getCode().trim(), addVO.getSource())) {
            return Wrapper.fail("菜单编码已经存在");
        }

        MenuCode menuCode = new MenuCode();
        menuCode.setCode(addVO.getCode().trim());
        menuCode.setSource(addVO.getSource());
        menuCode.setUrl(addVO.getUrl().trim());
        menuCode.setAttrs(CollectionUtils.isEmpty(addVO.getAttrs()) ? new HashMap<>() : addVO.getAttrs());
        menuCode.setRemark(StringUtils.isEmpty(addVO.getRemark()) ? "" : addVO.getRemark().trim());

        menuCodeRepository.saveAndFlush(menuCode);

        return Wrapper.success();
    }

    /**
     * 根据Id，修改菜单编码
     *
     * @param updateVO 接口参数
     * @return 操作结果
     */
    @Override
    public Wrapper<Void> updateMenuCode(MenuCodeUpdateVO updateVO) {
        if(menuCodeRepository.existsByCodeAndSourceAndIdNot(updateVO.getCode().trim(), updateVO.getSource(), updateVO.getId())) {
            return Wrapper.fail("菜单编码已经存在");
        }

        MenuCode menuCode = menuCodeRepository.findById(updateVO.getId()).orElse(null);
        if(menuCode == null) {
            return Wrapper.fail("菜单编码不存在");
        }

        menuCode.setCode(updateVO.getCode().trim());
        menuCode.setSource(updateVO.getSource());
        menuCode.setUrl(updateVO.getUrl().trim());
        menuCode.setAttrs(CollectionUtils.isEmpty(updateVO.getAttrs()) ? new HashMap<>() : updateVO.getAttrs());
        menuCode.setRemark(StringUtils.isEmpty(updateVO.getRemark()) ? "" : updateVO.getRemark().trim());

        menuCodeRepository.saveAndFlush(menuCode);

        return Wrapper.success();
    }

    /**
     * 根据Id,删除菜单编码
     *
     * @param idVO 接口参数
     * @return 操作结果
     */
    @Override
    public Wrapper<Void> deleteMenuCodeById(IdVO idVO) {
        menuCodeRepository.deleteById(idVO.getId());
        return Wrapper.success();
    }

    /**
     * 根据code、source查询一个菜单编码
     *
     * @param getVO 接口参数
     * @return 查询结果
     */
    @Override
    public Wrapper<MenuCodeVO> findMenuCode(MenuCodeGetVO getVO) {
        MenuCode menuCode = menuCodeRepository.findFirstByCodeAndSource(getVO.getCode().trim(), getVO.getSource());
        if(menuCode == null) {
            return Wrapper.fail("菜单编码不存在");
        }

        MenuCodeVO codeVO = new MenuCodeVO();
        codeVO.setId(menuCode.getId());
        codeVO.setCode(menuCode.getCode());
        codeVO.setUrl(menuCode.getUrl());
        codeVO.setSource(menuCode.getSource());
        codeVO.setRemark(menuCode.getRemark());
        codeVO.setAttrs(menuCode.getAttrs());

        return Wrapper.success(codeVO);
    }

    /**
     * 根据source，查询菜单编码列表
     *
     * @param sourceVO 接口参数
     * @return 查询结果
     */
    @Override
    public Wrapper<List<MenuCodeVO>> listMenuCode(MenuCodeSourceVO sourceVO) {
        List<MenuCode> menuCodeList;
        if(sourceVO.getSource() == null || sourceVO.getSource().equals(0)) {
            menuCodeList = menuCodeRepository.findAll(Sort.by("id").ascending());
        } else {
            menuCodeList = menuCodeRepository.findBySource(sourceVO.getSource(), Sort.by("id").ascending());
        }

        return Wrapper.success(menuCodeList.stream().map(menuCode -> {
            MenuCodeVO codeVO = new MenuCodeVO();
            codeVO.setId(menuCode.getId());
            codeVO.setCode(menuCode.getCode());
            codeVO.setUrl(menuCode.getUrl());
            codeVO.setSource(menuCode.getSource());
            codeVO.setRemark(menuCode.getRemark());
            codeVO.setAttrs(menuCode.getAttrs());
            return codeVO;
        }).collect(Collectors.toList()));
    }

    /**
     * 分页查询菜单编码列表
     *
     * @param pageVO 接口参数
     * @return 查询结果
     */
    @Override
    public Wrapper<PageData<MenuCodeVO>> pageMenuCode(MenuCodePageVO pageVO) {
        Specification<MenuCode> specification = (Specification<MenuCode>) (root, query, criteriaBuilder) -> {
            List<Predicate> list = new ArrayList<>();

            if(!StringUtils.isEmpty(pageVO.getCode())) {
                list.add(criteriaBuilder.like(root.get("code").as(String.class), "%" + pageVO.getCode().trim() + "%"));
            }

            if(pageVO.getSource() != null && !pageVO.getSource().equals(0)) {
                list.add(criteriaBuilder.equal(root.get("source").as(Integer.class), pageVO.getSource()));
            }

            Predicate[] p = new Predicate[list.size()];
            return criteriaBuilder.and(list.toArray(p));
        };

        Pageable page = PageRequest.of(pageVO.getCurrent() - 1, pageVO.getPageSize(), Sort.by("id").descending());
        Page<MenuCode> pageList = menuCodeRepository.findAll(specification, page);

        return Wrapper.success(new PageData<>(pageList.getTotalElements(), pageList.getContent().stream().map(menuCode -> {
            MenuCodeVO codeVO = new MenuCodeVO();
            codeVO.setId(menuCode.getId());
            codeVO.setCode(menuCode.getCode());
            codeVO.setUrl(menuCode.getUrl());
            codeVO.setSource(menuCode.getSource());
            codeVO.setRemark(menuCode.getRemark());
            codeVO.setAttrs(menuCode.getAttrs());
            return codeVO;
        }).collect(Collectors.toList())));
    }
}
